using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using FiltronASP.Logger;
using FiltronASP.Helpers.StringExtensions;

namespace FiltronASP.Models.DAO
{
    /// <summary>
    /// Klasa dla operacji bazodanowych specyficznych dla tabeli <code>pages</code>.
    /// </summary>
    public class PageDAO : Abstracts.AbstractGenericDAO<Page, System.Nullable<int>>,
        Interfaces.IPageDAO
    {
        /// <summary>
        /// Metoda zwracajaca nazwe parametru bedacego kluczem glownym tabeli.
        /// </summary>
        /// <returns>nazwa klucza glownego</returns>
        protected override string GetKeyProperty()
        {
            return "page_id";
        }

        /// <summary>
        /// Pobieranie listy obiektów na podstawie typu strony.
        /// </summary>
        /// <param name="pageTypeId">typ strony</param>
        /// <returns>Lista rekordów o zadanym typie strony</returns>
        public IQueryable<Page> FindByPageType(int pageTypeId)
        {
            if (pageTypeId.Equals(0))
            {
                return null;
            }   //if
            try
            {
                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => page.page_type_id.Equals(pageTypeId)
                        ).OrderBy(page => page.page_ordering);

                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

        /// <summary>
        /// Pobieranie listy obiektów na podstawie języka.
        /// </summary>
        /// <param name="languageId">język</param>
        /// <returns>Lista rekordów o zadanym języku</returns>
        public IQueryable<Page> FindByLanguage(int languageId)
        {
            if (languageId.Equals(0))
            {
                return null;
            }   //if
            try
            {
                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => page.language_id.Equals(languageId)
                        );

                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

        /// <summary>
        /// Pobieranie obiektu na podstawie języka, alliasu strony i linku do strony.
        /// </summary>
        /// <param name="languageId">język</param>
        /// <param name="pageAllias">allias</param>
        /// <param name="pageLink">Link</param>
        /// <returns>Rekord o zadanym języku, alliasie strony i linku do strony.</returns>
        public Page FindByLanguageAndAlliasAndLink(int languageId, string pageAllias, string pageLink)
        {
            if (languageId.Equals(0) || String.IsNullOrEmpty(pageAllias))
            {
                return null;
            }   //if
            try
            {
                if (String.IsNullOrEmpty(pageLink))
                {
                    return this._cmsEntitiesDataContext.Pages.SingleOrDefault(
                        page => page.language_id.Equals(languageId) && page.page_alias.Equals(pageAllias)
                            );
                }
                else
                {
                    return this._cmsEntitiesDataContext.Pages.SingleOrDefault(
                        page => page.language_id.Equals(languageId) && page.page_alias.Equals(pageAllias)
                            && page.page_link.Equals(pageLink)
                            );
                }
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }


        /// <summary>
        /// Pobieranie listy obiektów na podstawie języka, nazwy typu strony i informacji o publikacji.
        /// </summary>
        /// <param name="languageId">język</param>
        /// <param name="pageTypeName">nazwa typu strony</param>
        /// <param name="pagePublished">opublikowana</param>
        /// <returns>lista rekordow o zadanym języku, nazwie typu strony i informacji o publikacji.</returns>
        public IQueryable<Page> FindByLanguageAndTypeNameAndPublished(int languageId, string pageTypeName, bool pagePublished)
        {
            if (languageId.Equals(0) || String.IsNullOrEmpty(pageTypeName))
            {
                return null;
            }   //if
            try
            {
                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => page.language_id.Equals(languageId) && page.page_published.Equals(pagePublished)
                        && page.page_type_id.Equals(this._cmsEntitiesDataContext.PageTypes.SingleOrDefault(pate =>
                            pate.page_type_name.Equals(pageTypeName) && pate.language_id.Equals(languageId)).page_type_id)
                        ).OrderBy(page => page.page_ordering);

                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

        /// <summary>
        /// Pobieranie listy obiektów na podstawie języka, nazwy szablonu i informacji o publikacji.
        /// </summary>
        /// <param name="languageId">język</param>
        /// <param name="templateName">nazwa szablonu</param>
        /// <param name="pagePublished">opublikowana</param>
        /// <returns>lista rekordow o zadanym języku, id szablonu i informacji o publikacji.</returns>
        public IQueryable<Page> FindByLanguageAndTemplateNameAndPublished(int languageId, string templateName, bool pagePublished)
        {
            if (languageId.Equals(0) || String.IsNullOrEmpty(templateName))
            {
                return null;
            }   //if
            try
            {
                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => page.language_id.Equals(languageId) && page.page_published.Equals(pagePublished)
                        && page.template_id.Equals(this._cmsEntitiesDataContext.Templates.SingleOrDefault(temp =>
                            temp.template_name.Equals(templateName) && temp.language_id.Equals(languageId)).template_id)
                        );

                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

       


        /// <summary>
        /// Pobieranie listy obiektów na podstawie języka, nazwy szablonu i informacji o publikacji.
        /// </summary>
        /// <param name="languageId">język</param>
        /// <param name="templateId">id szablonu</param>
        /// <param name="pagePublished">opublikowana</param>
        /// <returns>lista rekordow o zadanym języku, nazwie szablonu i informacji o publikacji.</returns>
        public IQueryable<Page> FindByLanguageAndTemplateIdAndPublished(int languageId, int templateId, bool pagePublished)
        {
            if (languageId.Equals(0) || (templateId.Equals(0)))
            {
                return null;
            }   //if
            try
            {
                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => page.language_id.Equals(languageId) && page.template_id.Equals(templateId) 
                        && page.page_published.Equals(pagePublished)
                        );

                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

        /// <summary>
        /// Pobieranie listy obiektów na podstawie skrótu języka, nazwy typu strony i informacji o publikacji.
        /// </summary>
        /// <param name="languageAbbr">skrót języka</param>
        /// <param name="pageTypeName">nazwa typu strony</param>
        /// <param name="pagePublished">opublikowana</param>
        /// <returns>lista rekordow o zadanym skrócie języka, nazwie typu strony i informacji o publikacji.</returns>
        public IQueryable<Page> FindByLanguageAbbrAndTypeNameAndPublished(string languageAbbr, string pageTypeName, bool pagePublished)
        {
            if (String.IsNullOrEmpty(languageAbbr) || String.IsNullOrEmpty(pageTypeName))
            {
                return null;
            }   //if
            try
            {
                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => page.language_id.Equals(this._cmsEntitiesDataContext.Languages.SingleOrDefault(lang =>
                        lang.language_abbr.Equals(languageAbbr)).language_id) &&
                        page.page_published.Equals(pagePublished) &&
                        page.page_type_id.Equals(this._cmsEntitiesDataContext.PageTypes.SingleOrDefault(pate =>
                            pate.page_type_name.Equals(pageTypeName)).page_type_id)
                        );

                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }


        /// <summary>
        /// Pobieranie listy obiektów na podstawie skrótu języka, nazwy szablonu i informacji o publikacji.
        /// </summary>
        /// <param name="languageAbbr">skrót języka</param>
        /// <param name="templateName">nazwy szablonu</param>
        /// <param name="pagePublished">opublikowana</param>
        /// <returns>lista rekordow o zadanym skrócie języka, nazwie szablonu i informacji o publikacji.</returns>
        public IQueryable<Page> FindByLanguageAbbrAndTemplateNameAndPublished(string languageAbbr, string templateName, bool pagePublished)
        {
            if (String.IsNullOrEmpty(languageAbbr) || String.IsNullOrEmpty(templateName))
            {
                return null;
            }   //if
            try
            {
                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => page.language_id.Equals(this._cmsEntitiesDataContext.Languages.SingleOrDefault(lang =>
                        lang.language_abbr.Equals(languageAbbr)).language_id) && 
                        page.page_published.Equals(pagePublished) && 
                        page.template_id.Equals(this._cmsEntitiesDataContext.Templates.SingleOrDefault(temp =>
                            temp.template_name.Equals(templateName)).template_id)
                        );

                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

        /// <summary>
        /// Wstawianie listy obiektów na podstawie jezyka.
        /// </summary>
        /// <param name="defaultLanguageId">domyslny jezyk</param>
        /// <param name="newLanguageId">nowy jezyk</param>
        /// <returns>true jesli sie udalo, false wpp</returns>
        public bool InsertForNewLanguage(int defaultLanguageId, int newLanguageId)
        {
            if (defaultLanguageId.Equals(0) || newLanguageId.Equals(0))
            {
                return false;
            }   //if
            try
            {
                IQueryable<Page> pages = this.FindByLanguage(defaultLanguageId);
                TemplateDAO _templateDAO = new TemplateDAO();
                PageTypeDAO _pageTypeDAO = new PageTypeDAO();
                if (pages == null)
                {
                    return true;
                }   //if
                if (!(pages.Any()))
                {
                    return true;
                }   //if
                foreach (Page page in pages)
                {
                    Template oldTemp = _templateDAO.FindByPK(page.template_id);
                    if (oldTemp == null)
                    {
                        return false;
                    }
                    Template newTemp = _templateDAO.FindByLangAndName(newLanguageId, oldTemp.template_name);
                    if (newTemp == null)
                    {
                        return false;
                    }
                    PageType oldPageType = _pageTypeDAO.FindByPK(page.page_type_id);
                    if (oldPageType == null)
                    {
                        return false;
                    }
                    PageType newPageType = _pageTypeDAO.FindByNameAndLanguage(oldPageType.page_type_name, newLanguageId);
                    if (newPageType == null)
                    {
                        return false;
                    }
                    Page pageToInsert = new Page();
                    pageToInsert.language_id = newLanguageId;
                    pageToInsert.page_alias = page.page_alias;
                    pageToInsert.page_created = DateTime.Now;
                    pageToInsert.page_created_by_id = page.page_created_by_id;
                    pageToInsert.page_editable = page.page_editable;
                    pageToInsert.page_img = page.page_img;
                    pageToInsert.page_keywords = page.page_keywords;
                    pageToInsert.page_link = page.page_link;
                    pageToInsert.page_meta = page.page_meta;
                    pageToInsert.page_modified = DateTime.Now;
                    pageToInsert.page_modified_by_id = page.page_modified_by_id;
                    pageToInsert.page_name = page.page_name;
                    pageToInsert.page_ordering = page.page_ordering;
                    pageToInsert.page_published = page.page_published;
                    pageToInsert.page_removable = page.page_removable;
                    pageToInsert.page_type_id = newPageType.page_type_id;
                    pageToInsert.template_id = newTemp.template_id;
                    this.Add(pageToInsert);
                }

            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return true;
        }

        /// <summary>
        /// Pobieranie najwyższego porządku o zadanym typie strony.
        /// </summary>
        /// <param name="pageTypeId">typ strony</param>
        /// <param name="languageId">wersja jezykowa</param>
        /// <returns>Najwyższy porządek dla danego typu strony</returns>
        public int? SelectMaxPageOrdering(int pageTypeId, int languageId)
        {
            if (pageTypeId.Equals(0))
            {
                return 0;
            }   //if
            try
            {
                return this._cmsEntitiesDataContext.Pages.Where(
                    page => (page.page_type_id.Equals(pageTypeId)) && (page.language_id.Equals(languageId))
                ).Max(ma => ma.page_ordering);
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return 0;
        }

        /// <summary>
        /// Pobieranie najwyższego id dla stron.
        /// </summary>
        /// <param name="pageTypeId">typ strony</param>
        /// <returns>najwyższe id dla stron</returns>
        public int? SelectMaxPageId()
        {
            try
            {
                return this._cmsEntitiesDataContext.Pages.Max(ma => ma.page_id);
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return 0;
        }

        /// <summary>
        /// Metoda do aktualizacji porzadku stron.
        /// </summary>
        /// <param name="oldOrdering">poprzedni porzadek</param>
        /// <param name="newOrdering">nowy porzadek</param>
        /// <param name="pageTypeId">typ strony</param>
        /// <param name="languageId">wersja jezykowa</param>
        /// <param name="pageId">przesuwana strona</param>
        /// <returns></returns>
        public bool ReorderPages(int oldOrdering, int newOrdering, int pageTypeId, int languageId, int pageId)
        {
            try
            {
                if (oldOrdering == newOrdering)
                {
                    return true;
                }   //if
                if (oldOrdering < newOrdering)
                {
                   IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                    page => (page.page_type_id.Equals(pageTypeId)) && (page.language_id.Equals(languageId)) &&
                        (page.page_ordering > oldOrdering) && (page.page_ordering <= newOrdering)
                    );
                    foreach (Page page in pages)
                    {
                        page.page_ordering = page.page_ordering - 1;
                        if (!this.SubmitChanges())
                        {
                            Logger.MyLogger.Log("PageDAO warning: MassReorderPages method, unable to commit changes...");
                            return false;
                        }   //if
                    }   //foreach
                } else {    //if
                    IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                     page => (page.page_type_id.Equals(pageTypeId)) && (page.language_id.Equals(languageId)) &&
                         (page.page_ordering < oldOrdering) && (page.page_ordering >= newOrdering)
                    );
                    foreach (Page page in pages)
                    {
                        page.page_ordering = page.page_ordering + 1;
                        if (!this.SubmitChanges())
                        {
                            Logger.MyLogger.Log("PageDAO warning: MassReorderPages method, unable to commit changes...");
                            return false;
                        }   //if
                    }   //foreach
                }   //else    
                Page pageToMove = this.FindByPK(pageId);
                if (pageToMove != null)
                {
                    pageToMove.page_ordering = newOrdering;
                    return this.SubmitChanges();
                }   //if
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return false;
        }

        public Page FindByLanguageAlliasLinkAndNotId(int languageId, string pageAllias, string pageLink, int pageIdToExclude)
        {
            if (languageId <= 0 || String.IsNullOrEmpty(pageAllias) 
                || String.IsNullOrEmpty(pageLink) || pageIdToExclude <= 0)
            {
                return null;
            }   //if
            try
            {
                return this._cmsEntitiesDataContext.Pages.SingleOrDefault(
                    page => page.language_id.Equals(languageId) 
                        && page.page_alias.Equals(pageAllias)
                        && page.page_link.Equals(pageLink)
                        && page.page_id != pageIdToExclude
                );
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

        /// <summary>
        /// Usuwanie obiektow po jezyku.
        /// </summary>
        /// <param name="languageId">jezyk</param>
        /// <returns>true dla sukcesu, false w przeciwnym razie</returns>
        public bool DeleteByLanguage(int languageId)
        {
            if (languageId.Equals(0))
            {
                return false;
            }   //if
            try
            {
                IQueryable<Page> pages = this.FindByLanguage(languageId);
                if (pages == null)
                {
                    return true;
                }   //if
                if (!(pages.Any()))
                {
                    return true;
                }   //if
                foreach (Page page in pages)
                {
                    this._cmsEntitiesDataContext.Pages.DeleteOnSubmit(page);
                }
                try
                {
                    _cmsEntitiesDataContext.SubmitChanges();

                }
                catch (Exception ex)
                {
                    MyLogger.Log(ex);
                }   //catch
                return true;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return false;
        }

        /// <summary>
        /// Pobieranie wdrożeń/newsów po page_id, language_id i nazwie miesiąca
        /// </summary>
        public IQueryable<Page> findNewsByPageAndLanguageIdAndMonth(int languageId, string MonthName, string year, bool pagePublished)
        {
            if (languageId.Equals(0) || String.IsNullOrEmpty(MonthName))
            {
                return null;
            }   //if
            try
            {

                IQueryable<Page> pages = this._cmsEntitiesDataContext.Pages.Where(
                   page => (page.template_id.Equals(this._cmsEntitiesDataContext.Templates.SingleOrDefault(
                        temp => temp.template_name.Equals(String.Format("NewsSingle"))
                            && temp.language_id.Equals(languageId)).template_id
                       )) && page.language_id.Equals(languageId) && page.page_name.Contains(MonthName)
                       && page.page_name.Contains(year) 
                       && page.page_published.Equals(pagePublished)
                        );
                if (!(pages.Any()))
                {
                    return null;
                }   //if
                return pages;
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return null;
        }

        /// <summary>
        /// Aktualizacja linkow.
        /// </summary>
        /// <param name="defaultLanguageId">domyslny jezyk</param>
        /// <param name="newLanguageId">nowy jezyk</param>
        /// <returns>true jesli sie udalo, false wpp</returns>
        public bool UpdateLinksForNewLanguage(int newLanguageId)
        {
            if (newLanguageId <= 0)
            {
                return false;
            }   //if
            try
            {
                IQueryable<Page> pages = this.FindByLanguage(newLanguageId);
                if (pages == null)
                {
                    return true;
                }   //if
                if (!(pages.Any()))
                {
                    return true;
                }   //if
                foreach (Page page in pages)
                {
                    page.page_alias = this.GeneratePageAlias(page);
                    page.page_link = this.GeneratePageLink(page);
                    if (!this.SubmitChanges())
                    {
                        throw new Exception(String.Format("PageDAO exception: unable to update page link, pageId: {0}...", page.page_id));
                    }   //if
                }   //for
            }   //try
            catch (Exception ex)
            {
                MyLogger.Log(ex);
            }   //catch
            return true;
        }

        /// <summary>
        /// Metoda do generowania linka dla strony.
        /// </summary>
        /// <param name="page">strona</param>
        /// <returns>link</returns>
        private string GeneratePageLink(Page page)
        {
            if (page == null)
            {
                throw new Exception("PageDAO exception: GeneratePageLink method, page object null...");
            }   //if null
            return String.Format("{0},{1}.html", this.GeneratePageAlias(page), page.page_id);
        }

        /// <summary>
        /// Metoda do generowania aliasu dla strony.
        /// </summary>
        /// <param name="page">strona</param>
        /// <returns>alias</returns>
        private string GeneratePageAlias(Page page)
        {
            if (page == null)
            {
                throw new Exception("PageDAO exception: GeneratePageAlias method, page object null...");
            }   //if null
            return page.page_name.RemovePolishChars().RewriteToUrl();
        }

    }
}
